#pragma once 
#include <iostream>
#include <cstring>
#include <string>
#include <cerrno>
#include <cstdlib>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "err.hpp"
using namespace std;
namespace nt_server
{
    
    const uint16_t default_port = 8888;

    class UdpServer
    {
        
    public:
        UdpServer(const uint16_t port = default_port)
            :port_(port)
        {

        }

        ~UdpServer()
        {

        }

        void InitServer()
        {
            sock_ = socket(AF_INET, SOCK_DGRAM, 0);

            if(sock_ == -1)
            {
                cout << "Create Socket Fail: " << strerror(errno) << endl;
                exit(SOCKET_ERR);
            }

            cout << "Create Success Socket: " << sock_ << endl;

            //绑定IP地址和端口号
            struct sockaddr_in local;
            bzero(&local, sizeof(local));//0

            // 填充字段
            local.sin_family = AF_INET;// 设置为网络通信
            local.sin_port = htons(port_);// 主机序列转为网络序列
            //local.sin_addr.s_addr = inet_addr(ip_.c_str());// 点分十进制转为短整数，再将主机序列转为网络序列
            local.sin_addr.s_addr = INADDR_ANY;

            //绑定IP地址和端口号
            if(bind(sock_, (const sockaddr*)&local, sizeof(local)))
            {
                cout << "Bind IP&&Port Fail: " << strerror(errno) << endl; 
                exit(BIND_ERR);
            }
            //绑定成功
            cout << "Bind IP&&Port Success" << endl;
        }

        void StartServer()
        {
            char buff[1024];
            while(true)
            {
                //1.接收消息
                struct sockaddr_in peer;//客户端结构体
                socklen_t len = sizeof(peer);//客户端结构大小

                //传入sizeof(buff) - 1 表示当前传输的是字符串，预留一个位置存储'\0'
                //传入 0 表示当前是阻塞式读取
                
                ssize_t n = recvfrom(sock_, buff, sizeof(buff) - 1, 0, (struct sockaddr*)&peer, &len);
                if(n > 0)
                    buff[n] = '\0';
                else 
                    continue;

                //2.数据处理
                string clientIp = inet_ntoa(peer.sin_addr);
                uint16_t clientPort = ntohs(peer.sin_port);
                printf("Server get message from [%c:%d]$ %s\n",clientIp.c_str(), clientPort, buff);
                //3.回响给客户端
                n = sendto(sock_, buff, strlen(buff), 0, (const struct sockaddr*)&peer, sizeof(peer));
                if(n == -1)
                    cout << "Send Massage Fail: " << strerror(errno) << endl;
            }
        }

    private:
        int sock_;//套接字
        uint16_t port_;
        //string ip_;

    };
}
